
#include "Led.h"
#include "Debug.h"

Bool Led_SetState(Led* pLed, uint8 clr, uint8 function, uint8 onDuraton)
{
	uint8 color = 0;
	//int len = 1;

	pLed->m_LedStates.m_hasALocalCtrlState = False;
	if(clr <= 0x06)
	{
		if((1 << clr) & AS_UINT8(pLed->m_ColorCapabilities))
		{
			color = clr;
		}
		else
		{
			return False;
		}
	}
	else if(clr == 0x0E)	//Do not change
	{
		color = pLed->m_ColorInOverrideCtrlState;
	}
	else if(clr == 0x0F)	//Use default color
	{
		color = pLed->m_DefaultColorInOverrideCtrlState;
	}
	else
	{
		return False;
	}
	
    if(function == LEDFUN_OFF)
    {
		Led_SetWorkModeEx(pLed, OP_OFF, 0, 0,OVERRIDE_CONTROL, color);
    }
    else if(function == LEDFUN_ON)
    {
		Led_SetWorkModeEx(pLed, OP_ON, 0, 0,OVERRIDE_CONTROL, color);
    }
    else if(function >= LEDFUN_SHINE_MIX && function <= LEDFUN_SHINE_MAX)
    {
		Led_SetWorkModeEx(pLed, OP_SHINE, function*10, onDuraton*10, OVERRIDE_CONTROL, color);
    }
	else if(function == LEDFUN_LAMP_TEST)
	{
		if(onDuraton > 128) return False;
		
		return Led_LampTest(pLed, color, onDuraton*100);
	}
	else if(function == LEDFUN_LOCAL_CTRL)
	{
		Led_SetWorkModeEx(pLed, OP_OFF, 0, 0,LOCAL_CONTROL, color);
	}
	return True;
}

Bool Led_LampTest(Led* pLed, uint8 color, uint16 ms)
{	
	if(pLed->m_LedStates.m_isLampTestEnabled) return False;

	TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] Lamp test start: color=%d, time = %d ms\n", pLed->m_LedId, color, ms));
	pLed->m_ColorInLampTest = color;
	pLed->m_LampTestDuration = ms;
	pLed->m_LedStates.m_isLampTestEnabled = True;
	SwTimer_Start(&pLed->m_Timer, LAMP_TEST_TIMER_ID, ms);

	pLed->SetLed(pLed, color, True);

	return True;
}

void Led_SetWorkMode(Led* pLed, LedWorkMode mode, uint16 shineOff, uint16 ShineOn, uint8 Control)
{
	uint8 color = pLed->m_ColorInLocalCtrlState;
	if(LOCAL_CONTROL == Control)
	{
		pLed->m_LedStates.m_hasALocalCtrlState = True;
		color = pLed->m_DefaultColorInLocalCtrlState;
	}
	else
	{
		color = pLed->m_DefaultColorInOverrideCtrlState;
	}
	Led_SetWorkModeEx(pLed, mode, shineOff, ShineOn, Control, color);
}

void Led_SetWorkModeEx(Led* pLed, LedWorkMode mode, uint16 shineOff, uint16 ShineOn, uint8 Control, uint8 color)
{
	LedCmd ledCmd = {0};
	
	if(pLed->m_LedCmd.m_Off == shineOff
		&& pLed->m_LedCmd.m_On == ShineOn
		&& pLed->m_LedCmd.m_bWorkMode == mode
		&& (QUEUE_isEmpty(&pLed->m_Queue)))
	{
		return;
	}

	if((OP_INIT == pLed->m_LedCmd.m_bWorkMode 
		|| (QUEUE_isEmpty(&pLed->m_Queue) && pLed->m_bState >= LED_M3))
		&& pLed->m_LedStates.m_isLampTestEnabled == False)
	{
		TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] switch work mode to %d\n", pLed->m_LedId, mode));

		pLed->m_LedCmd.m_Off = shineOff;
		pLed->m_LedCmd.m_On = ShineOn;
		pLed->m_LedCmd.m_Color = color;
		pLed->m_LedCmd.m_bWorkMode = mode;
		
		pLed->m_Ticks = 0;
		if(OP_SHINE == mode || OP_ON == mode)
		{
			pLed->m_bState = LED_M1;
			if(pLed->SetLed)
				pLed->SetLed(pLed, color, True);
		}
		else
		{
			pLed->m_bState = LED_M2;
			if(pLed->SetLed)
				pLed->SetLed(pLed, color, False);
		}
	}
	else
	{
		
		if(QUEUE_isFull(&pLed->m_Queue))
		{
			QUEUE_popGetHead(&pLed->m_Queue);
		}
		ledCmd.m_Off = shineOff;
		ledCmd.m_On = ShineOn;
		ledCmd.m_bWorkMode = mode;
		QUEUE_add(&pLed->m_Queue, &ledCmd);
		TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] input LedCmd[%d] to Queue\n", pLed->m_LedId, mode));
	}

	if(OVERRIDE_CONTROL == Control)
	{
		pLed->m_LedStates.m_isOverrideStateEnabled = True;
		pLed->m_ColorInOverrideCtrlState = color;
	}
	else if(LOCAL_CONTROL == Control)
	{
		pLed->m_LedStates.m_isOverrideStateEnabled = False;
		pLed->m_ColorInLocalCtrlState = color;
	}
}

void Led_Timeout(SwTimer* pTimer, Led* pLed)
{
	LedCmd* pLedCmd = Null;

	if(LAMP_TEST_TIMER_ID == pTimer->m_bTimerId)
	{
		TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] Lamp test end\n", pLed->m_LedId));
		pLed->SetLed(pLed, pLed->m_DefaultColorInOverrideCtrlState, False);

		TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] switch work mode to %d\n", pLed->m_LedId, pLed->m_LedCmd.m_bWorkMode));
		if(pLed->m_LedCmd.m_bWorkMode == OP_ON)
		{
			pLed->SetLed(pLed, pLed->m_DefaultColorInOverrideCtrlState, True);
		}
		pLed->m_LedStates.m_isLampTestEnabled = False;
		pLed->m_LampTestDuration = 0;
	}
	
	SwTimer_Start(&pLed->m_Timer, SHINE_TIME_ID, LED_TIME);
	pLed->m_Ticks += LED_TIME;

	if(OP_SHINE == pLed->m_LedCmd.m_bWorkMode)
	{
		if(LED_M1 == pLed->m_bState || LED_M3 == pLed->m_bState)
		{
			if(pLed->m_Ticks >= pLed->m_LedCmd.m_Off)
			{
				pLed->SetLed(pLed, pLed->m_LedCmd.m_Color, False);
				pLed->m_Ticks = 0;
				pLed->m_bState += 1;
			}
		}
		else if(LED_M2 == pLed->m_bState || LED_M4 == pLed->m_bState)
		{
			if(pLed->m_Ticks >= pLed->m_LedCmd.m_On)
			{
				pLed->SetLed(pLed, pLed->m_LedCmd.m_Color, True);
				pLed->m_Ticks = 0;
				pLed->m_bState = LED_M3;
			}
		}
	}
	else
	{
		pLed->m_bState = LED_M3;
	}

	if(pLed->m_bState < LED_M3)
	{
		return;
	}
	
	if(!QUEUE_isEmpty(&pLed->m_Queue))
	{
		pLed->m_Ticks = 0;
		pLed->m_bState = LED_M1;
		
		pLedCmd = QUEUE_popGetHead(&pLed->m_Queue);
		memcpy(&pLed->m_LedCmd, pLedCmd, sizeof(LedCmd));

		TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] switch work mode to %d\n", pLed->m_LedId, pLed->m_LedCmd.m_bWorkMode));
		if(OP_SHINE == pLedCmd->m_bWorkMode)
		{
			pLed->SetLed(pLed, pLed->m_LedCmd.m_Color, True);
		}
		else
		{
			pLed->SetLed(pLed, pLed->m_LedCmd.m_Color, pLedCmd->m_bWorkMode == OP_ON);
		}
	}
}

void Led_Release(Led* pLed)
{
	if(pLed->m_pTimerManager)
		Timermanager_RemoveTimer(pLed->m_pTimerManager, &pLed->m_Timer);
	memset(pLed, 0, sizeof(Led));
}

int Led_GetState(Led* pLed, uint8* buff, uint8 len)
{
	int i = 0;
	
	buff[0] = AS_UINT8(pLed->m_LedStates);

	if(pLed->m_LedStates.m_isLampTestEnabled)
	{
		Assert(len >= 7);
		buff[1] = 0;
		buff[2] = 0;
		buff[3] = pLed->m_ColorInLocalCtrlState;
		buff[4] = LEDFUN_OFF;	//Override state LED Function
		buff[5] = LEDFUN_ON;
		buff[6] = pLed->m_ColorInLampTest;
		buff[7] = pLed->m_LampTestDuration / 100;
		i = 8;
	}
	else if(pLed->m_LedStates.m_isOverrideStateEnabled)
	{
		Assert(len >= 6);
		buff[1] = 0;
		buff[2] = 0;
		buff[3] = pLed->m_ColorInLocalCtrlState;
		buff[4] = pLed->m_LedCmd.m_Off / 10;
		buff[5] = pLed->m_LedCmd.m_On / 10;
		buff[6] = pLed->m_ColorInOverrideCtrlState;
		i = 7;
	}
	else if(pLed->m_LedStates.m_hasALocalCtrlState)
	{
		Assert(len >= 3);
		buff[1] = pLed->m_LedCmd.m_Off / 10;
		buff[2] = pLed->m_LedCmd.m_On / 10;
		buff[3] = pLed->m_ColorInLocalCtrlState;
		i = 4;
	}
	
	return i;
}


void Led_Init(Led* pLed, TimerManager* pTm,const LedItem* pLedItem, SetLedFun setLed)
{
	TRACE_LEVEL(TRACE_LED|TRACE_INTEG_TEST, ("LedId[%d] Init,  ColorCapabilities=0x%x\n", pLedItem->m_LedId, pLedItem->m_ColorCapabilities));

	memset(pLed, 0, sizeof(Led));
	
	pLed->m_LedId 							= pLedItem->m_LedId;
	pLed->m_DefaultColorInLocalCtrlState 	= pLedItem->m_DefaultColorInLocalCtrlState;
	pLed->m_DefaultColorInOverrideCtrlState = pLedItem->m_DefaultColorInOverrideCtrlState;
	AS_UINT8(pLed->m_ColorCapabilities) 	= pLedItem->m_ColorCapabilities;
	pLed->m_LedStates.m_hasALocalCtrlState			= True;
	pLed->SetLed 							= setLed;
	
	pLed->m_ColorInLocalCtrlState 		= pLedItem->m_DefaultColorInLocalCtrlState;
	pLed->m_ColorInOverrideCtrlState 	= pLedItem->m_DefaultColorInOverrideCtrlState;
	pLed->m_bState = LED_M0;
	
	pLed->m_pTimerManager = pTm;
	pLed->m_LedCmd.m_bWorkMode = OP_INIT;
	
	SwTimer_Init(&pLed->m_Timer, (TimeoutFun)Led_Timeout, pLed);
	Timermanager_AddTimer(pTm, &pLed->m_Timer);
	SwTimer_Start(&pLed->m_Timer, SHINE_TIME_ID, LED_TIME);
	
	QUEUE_init(&pLed->m_Queue, (uint8*)&pLed->m_QueueBuff, sizeof(LedCmd), MAX_CMD_COUNT);

	pLed->SetLed(pLed, pLed->m_DefaultColorInLocalCtrlState, False);
}


